package com.knife.autoconfigure.scheduler;

import com.knife.scheduler.config.KnifeSchedulerProperties;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.quartz.Scheduler;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

import javax.sql.DataSource;
import java.io.IOException;
import java.util.Objects;
import java.util.Properties;
import java.util.concurrent.*;

/**
 * 调度任务自动装配
 *
 * @author： 76875
 * @date： 2022/4/1 星期五 18:32
 * @description：
 * @modifiedBy：
 * @version: 1.0
 */
@Configuration
@ComponentScan(basePackages = {"com.knife.scheduler"})
@EnableConfigurationProperties(value = {KnifeSchedulerProperties.class})
public class KnifeSchedulerAutoConfigure {



    @Bean({"jobAsyncExecutor"})
    public ExecutorService commonAsyncTaskExecutor(KnifeSchedulerProperties config) {
        BasicThreadFactory.Builder builder = new BasicThreadFactory.Builder();
        ThreadFactory threadFactory = builder.namingPattern("KnifeSchedulerThreadPool-%d").build();
        ThreadPoolExecutor executor = new ThreadPoolExecutor(config.getCorePoolSize(),
                config.getMaxPoolSize(),
                0L,
                TimeUnit.MILLISECONDS,
                new SynchronousQueue<>(),
                threadFactory);
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }


    @Bean
    @ConditionalOnMissingBean(value = {MapperScannerConfigurer.class})
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setBasePackage("*.**.mapper");
        return mapperScannerConfigurer;
    }

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) throws IOException {
        PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
        propertiesFactoryBean.setLocation(new ClassPathResource("quartz.properties"));
        // 在quartz.properties中的属性被读取并注入后再初始化对象
        propertiesFactoryBean.afterPropertiesSet();
        // 创建SchedulerFactoryBean
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        Properties pro = propertiesFactoryBean.getObject();
        factory.setOverwriteExistingJobs(true);
        factory.setAutoStartup(true);
        factory.setQuartzProperties(Objects.requireNonNull(pro));
        factory.setDataSource(dataSource);
        return factory;
    }


    /**
     * 通过SchedulerFactoryBean获取Scheduler的实例
     */
    @Bean
    public Scheduler scheduler(SchedulerFactoryBean schedulerFactoryBean) throws IOException {
        return schedulerFactoryBean.getScheduler();
    }

}
